Skip to content

fix(hilbert): support offset-centre circular masks - #313

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/hilbert-offset-centre-mask
May 15, 2026
Merged

Jammy2211 merged 1 commit into
mainfrom
feature/hilbert-offset-centre-mask

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Summary

Fixes a user-reported bug where Hilbert image-mesh raised PixelizationException for circular masks with offset centres (e.g. lens systems whose mask centre is not at the field-of-view origin). The bug had two compounding halves: Mask2D.is_circular returned False for genuinely circular offset masks due to pixel-quantization asymmetry, and even if the check were bypassed the Hilbert sampler always probed the image around (0, 0) rather than the mask centre.

API Changes

  • Mask2D.is_circular is now quantization-robust and correctly distinguishes filled discs from annular and square masks (previously annular masks were false-positives).
  • Mask2D.circular_radius derives the radius from the bbox extent. Numerically identical for centred masks.
  • hilbert.image_and_grid_from gains an optional mask_centre=(0.0, 0.0) parameter and translates the Hilbert sample points by it. For masks centred at the origin (every current test/smoke case) this is a no-op.

See full details below.

Test Plan

  • New tests in test_autoarray/mask/test_mask_2d.py cover offset centres (5 parametrised positions), annular masks, square unmasked regions, and circular_radius for offset centres.
  • New test in test_autoarray/inversion/pixelization/image_mesh/test_hilbert.py asserts that the resulting mesh points lie inside the mask's circle for an offset-centre mask.
  • Existing centred-mask Hilbert test returns the same bit-exact mesh point ([-1.02590674, -1.70984456]), confirming Delaunay-Hilbert smoke tests will produce unchanged likelihoods.
  • Full mask suite (72 tests) and full inversion suite (165 tests) pass with no regressions.
Full API Changes (for automation & release notes)

Changed Behaviour

  • Mask2D.is_circular — algorithm rewritten. Now returns True for offset-centre circular masks (was: returned False when centre offset caused pixel-quantization asymmetry). Now returns False for annular masks (was: returned True because central row/column counts were symmetric).
  • Mask2D.circular_radius — computed from the bounding-box extent of the unmasked region (was: from the unmasked-pixel count in a single guessed central row). Numerically identical for centred masks; correct rather than spurious for offset centres.

Changed Signature

  • autoarray.inversion.mesh.image_mesh.hilbert.image_and_grid_from(image, mask, mask_radius, pixel_scales, hilbert_length, mask_centre=(0.0, 0.0)) — new trailing keyword mask_centre, defaults to (0.0, 0.0) so existing callers are unaffected.

Migration

None required. All changes are either additive (new optional kwarg with backward-compatible default) or strictly bug-fix behaviour. Workspaces and tests using centred masks see no numerical change.

🤖 Generated with Claude Code

Previously Hilbert image-mesh raised PixelizationException for offset-centre
circular masks whose centres didn't land on a pixel half-integer, and would
have silently sampled the wrong region of the image for those that slipped
through. This commit fixes both halves of the bug.

- Mask2D.is_circular rewritten to be quantization-robust: bbox square within
  one pixel, geometric centre pixel unmasked, and a reference circular mask
  reconstructed from the inferred centre+radius must match the input within
  rim quantization tolerance. The new predicate correctly accepts offset
  circles and rejects annular and square masks that previously false-passed.
- Mask2D.circular_radius now derives the radius from the bbox extent rather
  than the central row count. Numerically identical for centred masks; correct
  for offset centres.
- hilbert.image_and_grid_from now translates Hilbert sample points by
  mask_centre, so the curve actually probes the masked region of the image.
  For masks centred at the origin (every current test/smoke case) the shift
  is a no-op and likelihoods are bit-identical.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Jammy2211 Jammy2211 added the pending-release PR queued for the next release build label May 15, 2026
@Jammy2211
Jammy2211 merged commit f484332 into main May 15, 2026
6 checks passed
@Jammy2211
Jammy2211 deleted the feature/hilbert-offset-centre-mask branch May 15, 2026 15:03
@Jammy2211 Jammy2211 removed the pending-release PR queued for the next release build label Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant